/*  @(#) include/amqsvmha.h, samples, p000, p000-L041117 1.48 04/11/16 10:05:41 */
 /********************************************************************/
 /*                                                                  */
 /* Module Name: AMQSVMHA.H                                          */
 /*                                                                  */
 /* Description: Sample Data Conversion macros for use in            */
 /*              conjunction with the Data Conversion                */
 /*              exit-generation utility program.                    */
 /*                                                                  */
 /* <N_OCO_COPYRIGHT>                                                */
 /* Licensed Materials - Property of IBM                             */
 /*                                                                  */
 /* 63H9336                                                          */
 /* (c) Copyright IBM Corp. 1994, 2005 All Rights Reserved.          */
 /*                                                                  */
 /* US Government Users Restricted Rights - Use, duplication or      */
 /* disclosure restricted by GSA ADP Schedule Contract with          */
 /* IBM Corp.                                                        */
 /* <NOC_COPYRIGHT>                                                  */
 /********************************************************************/
 /*                                                                  */
 /* Function:                                                        */
 /*                                                                  */
 /*   AMQSVMHA is a sample collection of macros to resolve the       */
 /*   macro calls generated by the Data Conversion exit-generation   */
 /*   utility.                                                       */
 /*     These macros make references to variables declared in the    */
 /*   sample Data Conversion exit routine AMQSVFC0.C.                */
 /*     The macros provided are:                                     */
 /*                                                                  */
 /*     AlignShort()                                                 */
 /*     AlignLong()                                                  */
 /*     AlignInt32()                                                 */
 /*     AlignInt64()                                                 */
 /*     ConvertByte()                                                */
 /*     ConvertChar()                                                */
 /*     ConvertVarChar()                                             */
 /*     ConvertShort()                                               */
 /*     ConvertLong()                                                */
 /*     ConvertInt32()                                               */
 /*     ConvertInt64()                                               */
 /*                                                                  */
 /********************************************************************/

 /* Protect against accidental double inclusion */
 #ifndef AMQSVMHA_DEFINED
 #define AMQSVMHA_DEFINED

 /********************************************************************/
 /* Include files                                                    */
 /********************************************************************/

 #include <string.h>      /* For memcpy                              */
 #include <cmqc.h>        /* Message Queueing Interface definitions  */
 #include <cmqxc.h>       /* MQI exit-related definitions            */
 #include <stdio.h>

 /********************************************************************/
 /* Macros                                                           */
 /********************************************************************/

 /********************************************************************/
 /* CheckSpace(n, size, rcode)                                       */
 /*     n is the number of elements in the field (MQLONG)            */
 /*     size is the number of bytes in one element (MQLONG)          */
 /*     rcode is the return code from this macro (only set on error) */
 /*   This macro is called by the following macros to check that     */
 /*   there is enough space remaining in both the input and output   */
 /*   buffers to convert the next field.  If there is not, then it   */
 /*   reduces the value of n accordingly and sets rc to the          */
 /*   appropriate return code.                                       */
 /*   In some cases it is not an error if the input buffer is too    */
 /*   small to contain an entire message of the current format. For  */
 /*   example an application browsing the first 100 bytes of each    */
 /*   message on a queue where some of the messages are of a format  */
 /*   of more than 100 bytes. The CheckSpace macro uses the          */
 /*   MQxx_EXPECT_TRUNCATED_INPUT to identify if the data conversion */
 /*   routine is sympathetic to a truncated input buffer. If so then */
 /*   we expect the conversion routine to convert up to the end of   */
 /*   the last complete field. It's the applications business        */
 /*   whether it can then cope with the truncated message.           */
 /*   The value of rc depends on whether or not the original message */
 /*   was truncated and on whether or not the requesting application */
 /*   will accept a truncated message.                               */
 /********************************************************************/
 #ifdef MQxx_EXPECT_TRUNCATED_INPUT
 #define CheckSpace(n, size, rcode)                                   \
 if ((MQLONG)(in_lastbyte - *in_cursor + 1) < n*size)                \
 {                                                                    \
   n = ((MQLONG)(in_lastbyte - *in_cursor + 1) / size);               \
 }                                                                    \
 if ((MQLONG) (out_lastbyte - *out_cursor + 1) < n*size)              \
 {                                                                    \
   n = ((MQLONG)(out_lastbyte - *out_cursor + 1) / size);             \
   rcode = (opts & MQGMO_ACCEPT_TRUNCATED_MSG)                        \
           ? MQRC_TRUNCATED_MSG_ACCEPTED                              \
           : MQRC_CONVERTED_MSG_TOO_BIG;                              \
 }
 #else
 #define CheckSpace(n, size, rcode)                                   \
 if ((MQLONG) (in_lastbyte - *in_cursor + 1) < n*size)                \
 {                                                                    \
   n = ((MQLONG)(in_lastbyte - *in_cursor + 1) / size);               \
   rcode = (Reason == MQRC_TRUNCATED_MSG_ACCEPTED)                    \
           ? MQRC_TRUNCATED_MSG_ACCEPTED                              \
           : MQRC_NOT_CONVERTED;                                      \
 }                                                                    \
 if ((MQLONG) (out_lastbyte - *out_cursor + 1) < n*size)              \
 {                                                                    \
   n = ((MQLONG)(out_lastbyte - *out_cursor + 1) / size);             \
   rcode = (opts & MQGMO_ACCEPT_TRUNCATED_MSG)                        \
           ? MQRC_TRUNCATED_MSG_ACCEPTED                              \
           : MQRC_CONVERTED_MSG_TOO_BIG;                              \
 }
 #endif

 /********************************************************************/
 /* AlignShort()                                                     */
 /*   - Aligns the cursors suitably for a 2-byte field.              */
 /*     The default alignment rule is for all structures to be       */
 /*     packed.  If your structures follow a different alignment     */
 /*     rule then this macro will need changing appropriately.       */
 /********************************************************************/
 #define AlignShort()

 /********************************************************************/
 /* AlignLong()                                                      */
 /* AlignInt32()                                                     */
 /*   - Aligns the cursors suitably for a 4-byte field.              */
 /*     The default alignment rule is for all structures to be       */
 /*     packed.  If your structures follow a different alignment     */
 /*     rule then this macro will need changing appropriately.       */
 /********************************************************************/
 #define AlignLong()
 #define AlignInt32 AlignLong
 
 /********************************************************************/
 /* AlignInt64()                                                     */
 /*   - Aligns the cursors suitably for an 8-byte field.             */
 /*     The default alignment rule is for all structures to be       */
 /*     packed.  If your structures follow a different alignment     */
 /*     rule then this macro will need changing appropriately.       */
 /********************************************************************/
 #define AlignInt64()
 
 /********************************************************************/
 /* ConvertChar(cnumber)                                             */
 /*   - Converts the next cnumber bytes starting at in_cursor from   */
 /*     characters in MsgCCSID into characters in ReqCCSID starting  */
 /*     at out_cursor.                                               */
 /*     This macro supports Multibyte Characters. The options value  */
 /*     MQDCC_FILL_TARGET_BUFFER will ensure that the converted      */
 /*     charactes fill the buffer, using padding or truncation rules */
 /*     details of which can be found in the MQ documents.           */
 /*     If the characters will not fit after truncation the          */
 /*     Reason code is set to MQRC_STRING_TOO_BIG.                   */
 /*     The options parameter is also set to allow the correct       */
 /*     interpretation of the UCS2 encoding of UNICODE.              */
 /********************************************************************/
 #define ConvertChar(cnumber)                                         \
 {                                                                    \
   MQLONG outlength, cc, rc, rc0;                                     \
   MQLONG options;                                                    \
   MQLONG cn = cnumber;                                               \
                                                                      \
   options = MQDCC_FILL_TARGET_BUFFER                                 \
   + ((MsgEncoding & MQENC_INTEGER_MASK) * MQDCC_SOURCE_ENC_FACTOR)   \
   + ((ReqEncoding & MQENC_INTEGER_MASK) * MQDCC_TARGET_ENC_FACTOR);  \
                                                                      \
   rc0 = MQRC_NONE;                                                   \
   CheckSpace(cn, 1, rc0);                                            \
   MQXCNVC(hConn,                                                     \
           options,                                                   \
           MsgCCSID,                                                  \
           cn,                                                        \
           (PMQCHAR)*in_cursor,                                       \
           ReqCCSID,                                                  \
           cn,                                                        \
           (PMQCHAR)*out_cursor,                                      \
           &outlength,                                                \
           &cc,                                                       \
           &rc);                                                      \
                                                                      \
                                                                      \
   if (rc0 == MQRC_NONE)                                              \
   {                                                                  \
      if (rc == MQRC_NONE)                                            \
      {                                                               \
         *in_cursor  += cn;                                           \
         *out_cursor += cn;                                           \
      }                                                               \
      else if ((rc == MQRC_CONVERTED_MSG_TOO_BIG) ||                  \
               (rc == MQRC_CONVERTED_STRING_TOO_BIG))                 \
      {                                                               \
         if (opts & MQGMO_ACCEPT_TRUNCATED_MSG)                       \
         {                                                            \
            ReturnCode = MQRC_TRUNCATED_MSG_ACCEPTED;                 \
         }                                                            \
         else                                                         \
         {                                                            \
            ReturnCode = MQRC_CONVERTED_STRING_TOO_BIG;               \
            goto Fail;                                                \
         }                                                            \
      }                                                               \
      else                                                            \
      {                                                               \
         ReturnCode = rc;                                             \
         goto Fail;                                                   \
      }                                                               \
   }                                                                  \
   else                                                               \
   {                                                                  \
      ReturnCode = rc0;                                               \
      goto Fail;                                                      \
   }                                                                  \
}

 /********************************************************************/
 /* ConvertVarChar                                                   */
 /*   - Converts characters to the end of the message.  This macro   */
 /*     can be used with Multibyte character fields.                 */
 /*     The options parameter is set to allow the correct            */
 /*     interpretation of the UCS2 encoding of UNICODE.              */
 /********************************************************************/
 #define ConvertVarChar()                                             \
 {                                                                    \
   MQLONG cn, ocn, cc, rc;                                            \
   MQLONG options;                                                    \
   PMQBYTE loop, last_sig_byte;                                       \
   options =                                                          \
     ((MsgEncoding & MQENC_INTEGER_MASK) * MQDCC_SOURCE_ENC_FACTOR)   \
   + ((ReqEncoding & MQENC_INTEGER_MASK) * MQDCC_TARGET_ENC_FACTOR);  \
                                                                      \
   cn = (MQLONG)(in_lastbyte - *in_cursor + 1);                                 \
   ocn = (MQLONG)(out_lastbyte - *out_cursor + 1);                              \
   last_sig_byte = *out_cursor + cn - 1;                              \
   MQXCNVC(hConn,                                                     \
           options,                                                   \
           MsgCCSID,                                                  \
           cn,                                                        \
  (PMQCHAR)*in_cursor,                                                \
           ReqCCSID,                                                  \
           ocn,                                                       \
  (PMQCHAR)*out_cursor,                                               \
          &ocn,                                                       \
          &cc,                                                        \
          &rc);                                                       \
  if (((*out_cursor+ocn) <= out_lastbyte) &&                          \
      (rc == MQRC_CONVERTED_MSG_TOO_BIG) &&                           \
      (opts & MQGMO_ACCEPT_TRUNCATED_MSG) ||                          \
      (ocn < cn))                                                     \
   {                                                                  \
      for (loop = *out_cursor+ocn; loop <= last_sig_byte; loop++)     \
      {                                                               \
         *loop = '\0';                                                \
      }                                                               \
   }                                                                  \
   if (rc == MQRC_NONE)                                               \
   {                                                                  \
     *in_cursor  += cn;                                               \
     *out_cursor += ocn;                                              \
   }                                                                  \
   else if ((rc == MQRC_CONVERTED_MSG_TOO_BIG) ||                     \
            (rc == MQRC_CONVERTED_STRING_TOO_BIG) ||                  \
            (rc == MQRC_DBCS_ERROR ))                                 \
   {                                                                  \
     if (opts & MQGMO_ACCEPT_TRUNCATED_MSG)                           \
     {                                                                \
       ReturnCode = MQRC_TRUNCATED_MSG_ACCEPTED;                      \
       *in_cursor  += cn;                                             \
       *out_cursor += ocn;                                            \
     }                                                                \
     else                                                             \
     {                                                                \
       if (rc == MQRC_CONVERTED_MSG_TOO_BIG)                          \
       {                                                              \
          ReturnCode = MQRC_CONVERTED_STRING_TOO_BIG;                 \
       }                                                              \
       else                                                           \
       {                                                              \
          ReturnCode = rc;                                            \
       }                                                              \
       goto Fail;                                                     \
     }                                                                \
   }                                                                  \
   else                                                               \
   {                                                                  \
      ReturnCode = rc;                                                \
   }                                                                  \
 }

 /********************************************************************/
 /* ConvertByte                                                      */
 /*   - Copies over bnumber bytes from input buffer to output buffer */
 /********************************************************************/
 #define ConvertByte(bnumber)                                         \
 {                                                                    \
   MQLONG bn = (MQLONG)(bnumber);                                     \
   MQLONG rc0 = 0;                                                    \
   CheckSpace(bn, 1, rc0);                                            \
   memcpy(*out_cursor, *in_cursor, bn);                               \
   *in_cursor  += bn;                                                 \
   *out_cursor += bn;                                                 \
   if (rc0 != MQRC_NONE)                                              \
   {                                                                  \
     ReturnCode = rc0;                                                \
     goto Fail;                                                       \
   }                                                                  \
 }

 /********************************************************************/
 /* ConvertShort                                                     */
 /*   - Converts snumber 2-byte integers from MsgEncoding to         */
 /*     ReqEncoding                                                  */
 /********************************************************************/
 #define ConvertShort(snumber)                                        \
 { MQLONG EncIn, EncOut;                                              \
   MQLONG i;                                                          \
   MQLONG sn = (MQLONG)(snumber);                                     \
   MQLONG rc0 = 0;                                                    \
                                                                      \
   CheckSpace(sn, 2, rc0);                                            \
   EncIn  = MsgEncoding & MQENC_INTEGER_MASK;                         \
   EncOut = ReqEncoding & MQENC_INTEGER_MASK;                         \
                                                                      \
   if (EncIn == EncOut)                                               \
     { ConvertByte(2*sn); }                                           \
   else                                                               \
   if ((EncOut != MQENC_INTEGER_NORMAL) &&                            \
       (EncOut != MQENC_INTEGER_REVERSED))                            \
   { ReturnCode = MQRC_TARGET_INTEGER_ENC_ERROR;                      \
     goto Fail; }                                                     \
   else                                                               \
   if ((EncIn != MQENC_INTEGER_NORMAL) &&                             \
       (EncIn != MQENC_INTEGER_REVERSED))                             \
   { ReturnCode = MQRC_SOURCE_INTEGER_ENC_ERROR;                      \
     goto Fail; }                                                     \
   else for (i = 0; i < sn; i++)                                      \
   { **out_cursor       = *(*in_cursor + 1);                          \
     *(*out_cursor + 1) = *(*in_cursor);                              \
     *in_cursor  += 2;                                                \
     *out_cursor += 2; }                                              \
   if (rc0 != MQRC_NONE)                                              \
   {                                                                  \
     ReturnCode = rc0;                                                \
     goto Fail;                                                       \
   }                                                                  \
 }

 /********************************************************************/
 /* ConvertLong                                                      */
 /* ConvertInt32                                                     */
 /*   - Converts lnumber 4-byte integers from MsgEncoding to         */
 /*     ReqEncoding                                                  */
 /********************************************************************/
 #define ConvertLong(lnumber)                                         \
 { MQLONG EncIn, EncOut;                                              \
   MQLONG i;                                                          \
   MQLONG ln = lnumber;                                               \
   MQLONG rc0 = 0;                                                    \
                                                                      \
   CheckSpace(ln, 4, rc0);                                            \
   EncIn  = MsgEncoding & MQENC_INTEGER_MASK;                         \
   EncOut = ReqEncoding & MQENC_INTEGER_MASK;                         \
                                                                      \
   if (EncIn == EncOut)                                               \
     { ConvertByte(4*ln); }                                           \
   else                                                               \
   if ((EncOut != MQENC_INTEGER_NORMAL) &&                            \
       (EncOut != MQENC_INTEGER_REVERSED))                            \
   { ReturnCode = MQRC_TARGET_INTEGER_ENC_ERROR;                      \
     goto Fail; }                                                     \
   else                                                               \
   if ((EncIn != MQENC_INTEGER_NORMAL) &&                             \
       (EncIn != MQENC_INTEGER_REVERSED))                             \
   { ReturnCode = MQRC_SOURCE_INTEGER_ENC_ERROR;                      \
     goto Fail; }                                                     \
   else for (i = 0; i < ln; i++)                                      \
   { **out_cursor       = *(*in_cursor + 3);                          \
     *(*out_cursor + 1) = *(*in_cursor + 2);                          \
     *(*out_cursor + 2) = *(*in_cursor + 1);                          \
     *(*out_cursor + 3) = **in_cursor;                                \
     *in_cursor  += 4;                                                \
     *out_cursor += 4; }                                              \
   if (rc0 != MQRC_NONE)                                              \
   {                                                                  \
     ReturnCode = rc0;                                                \
     goto Fail;                                                       \
   }                                                                  \
 }
 #define ConvertInt32 ConvertLong

 /********************************************************************/
 /* ConvertInt64                                                     */
 /*   - Converts lnumber64 8-byte integers from MsgEncoding to       */
 /*     ReqEncoding                                                  */
 /********************************************************************/
 #define ConvertInt64(lnumber)                                        \
 { MQLONG EncIn, EncOut;                                              \
   MQLONG i;                                                          \
   MQLONG ln = lnumber;                                               \
   MQLONG rc0 = 0;                                                    \
                                                                      \
   CheckSpace(ln, 8, rc0);                                            \
   EncIn  = MsgEncoding & MQENC_INTEGER_MASK;                         \
   EncOut = ReqEncoding & MQENC_INTEGER_MASK;                         \
                                                                      \
   if (EncIn == EncOut)                                               \
     { ConvertByte(8*ln); }                                           \
   else                                                               \
   if ((EncOut != MQENC_INTEGER_NORMAL) &&                            \
       (EncOut != MQENC_INTEGER_REVERSED))                            \
   { ReturnCode = MQRC_TARGET_INTEGER_ENC_ERROR;                      \
     goto Fail; }                                                     \
   else                                                               \
   if ((EncIn != MQENC_INTEGER_NORMAL) &&                             \
       (EncIn != MQENC_INTEGER_REVERSED))                             \
   { ReturnCode = MQRC_SOURCE_INTEGER_ENC_ERROR;                      \
     goto Fail; }                                                     \
   else for (i = 0; i < ln; i++)                                      \
   { **out_cursor       = *(*in_cursor + 7);                          \
     *(*out_cursor + 1) = *(*in_cursor + 6);                          \
     *(*out_cursor + 2) = *(*in_cursor + 5);                          \
     *(*out_cursor + 3) = *(*in_cursor + 4);                          \
     *(*out_cursor + 4) = *(*in_cursor + 3);                          \
     *(*out_cursor + 5) = *(*in_cursor + 2);                          \
     *(*out_cursor + 6) = *(*in_cursor + 1);                          \
     *(*out_cursor + 7) = **in_cursor;                                \
     *in_cursor  += 8;                                                \
     *out_cursor += 8; }                                              \
   if (rc0 != MQRC_NONE)                                              \
   {                                                                  \
     ReturnCode = rc0;                                                \
     goto Fail;                                                       \
   }                                                                  \
 }
 
 #endif
